package com.xiyuan.smartutils.seqs;

import com.xiyuan.smartutils.*;

import java.util.Calendar;

/**
 * 整型序列值，默认从1从0x7FFFFFFF(最大值)，每天重新开始，并支持保存文件<br><br>
 * 1、最小值必须>=1<br>
 * 2、如果设置最大值，则最大值必须大小最小值，否则取整数最大值0x7FFFFFFF<br>
 * 3、是否自动保存
 *
 * @version v1.0.0 @author lgz 2017-8-27 新建与整理
 */
public class SequenceDateFile extends SequenceFile {
    private static final long DAY_MS = 24 * 3600 * 1000;
    
    private long zone;
    private volatile long date;
    
    /***********************************************************************************/
    //默认自动加载
    /***********************************************************************************/
    
    /**
     * 从1到0x7FFFFFFF，自动加载
     */
    public SequenceDateFile(String filePath) {
        super(filePath);
    }
    
    /**
     * 从1到len个9，自动加载
     */
    public SequenceDateFile(int len, String filePath) {
        super(len, filePath);
    }
    
    /**
     * 从min到max，自动加载
     */
    public SequenceDateFile(long min, long max, String filePath) {
        super(min, max, min, filePath);
    }
    
    /**
     * 从min到max，指定初始值，自动加载
     */
    public SequenceDateFile(long min, long max, long seq, String filePath) {
        super(min, max, seq, filePath);
    }
    
    /***********************************************************************************/
    //设置自动/手动加载，一般用于手动加载
    /***********************************************************************************/
    
    /**
     * 从1到0x7FFFFFFF
     */
    public SequenceDateFile(String filePath, boolean auto) {
        super(filePath, auto);
    }
    
    /**
     * 从1到len个9
     */
    public SequenceDateFile(int len, String filePath, boolean auto) {
        super(len, filePath, auto);
    }
    
    /**
     * 从min到max
     */
    public SequenceDateFile(long min, long max, String filePath, boolean auto) {
        super(min, max, filePath, auto);
    }
    
    /**
     * 从min到max，指定初始值
     */
    public SequenceDateFile(long min, long max, long seq, String filePath, boolean auto) {
        super(min, max, seq, filePath, auto);
    }
    
    public String getDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date * DAY_MS);
        return DateTimes.toDateString(calendar);
    }
    
    /********************************************************************/
    //判断日期加载和保存序列号，自动标志打开时，新建即加载，每次next即保存
    
    /********************************************************************/
    
    @Override
    protected void init() {
        zone = DateTimes.toLong("1970-01-01 00:00:00");
        date = (System.currentTimeMillis() - zone) / DAY_MS;
    }
    
    @Override
    public SequenceDateFile load() {
        String seqs = readFile();
        if (Validates.isEmpty(seqs)) {return this;}
        
        String[] daySeq = Arrays.toStringArray(seqs);
        if (daySeq.length != 2) {return this;}
        
        long day = Longs.toLong(StrUtils.trim(daySeq[0]), -1);
        if (day != date) {return this;}
        
        String seq = StrUtils.trim(daySeq[1]);
        if (!Validates.isIntegerPositive(seq)) {return this;}
        
        setSequence(Longs.toLong(seq));
        return this;
    }
    
    @Override
    public void save() {//日期取10位最大整型，序列号取19位最大长整型，不足后补空格，保证每次写入时完整
        String day = StrUtils.suffixLen(date, 10, _SPACE_);
        String seq = StrUtils.suffixLen(sequence.get(), 19, _SPACE_);
        writeFile(new StringBuilder(day).append(",").append(seq).toString());
    }
    
    /********************************************************************/
    //重写获取方法，按天判断，和IntSequenceDate中的方法相同
    
    /********************************************************************/
    
    @Override
    public long next() {
        if (!isValid()) {//创建就失败，但不在构造函数中报错，而在使用时报异常
            throw Asserts.exception("创建SequenceFile失败，文件目录不存在且创建失败");
        }
        
        synchronized (this) {
            long day = (System.currentTimeMillis() - zone) / DAY_MS;
            if (day == date) {
                // 当天的检查是否序列号回归
                chkSequence();
            }
            else {
                //跨天了重置序列号为最小值，并置日期为当前日期
                super.reset();
                date = day;
            }
            
            long seq = sequence.incrementAndGet();
            if (isAuto()) {//保存下一个，返回当前
                save();
            }
            return seq;
        }
    }
}
